package pseudoAssemblerCompiler.twopassassembler.view.ui.autocomplete;

import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.IControlContentAdapter2;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * User: Selivanov
 * Date: 08.05.12
 * Time: 0:01
 */
public class AutoCompleteCombo<T> extends Composite {
    private ContentProposalAdapter adapter;


    private List<T> data;
    private Map<String, ComboDisplayFormatContentProposal> contentProposals;
    private Map<String, T> idToItems = new HashMap<String, T>();
    private ComboDisplayFormat<T> displayFormat;
    private Text text;

    private T selected = null;

    public T getSelected() {
        return selected;
    }

    public void setSelected(T selected) {
        this.selected = selected;
    }

    private List<ItemSelectionListener<T>> listeners = new ArrayList<ItemSelectionListener<T>>();

    public void addSelectionListener(ItemSelectionListener<T> selectionListener) {
        listeners.add(selectionListener);
    }

    public void removeSelectionListener(ItemSelectionListener<T> selectionListener) {
        listeners.remove(selectionListener);
    }

    protected void fireItemSelected(T item) {
        for (ItemSelectionListener<T> listener : listeners) {
            listener.itemSelected(item);
        }
    }

    public String getText() {
        return text.getText();
    }

    public void setText(String text) {
        if (allowText) this.text.setText(text);
    }

    private boolean allowText = true;


    private IContentProposalProvider provider = new IContentProposalProvider() {
        Map<String, IContentProposal[]> cache = new HashMap<String, IContentProposal[]>();

        @Override
        public IContentProposal[] getProposals(String contents, int position) {
            // Фильтрация по displayName

            IContentProposal[] resultArray = cache.get(contents);
            if (resultArray != null) {
                return resultArray;
            }

            List<ComboDisplayFormatContentProposal> result = new ArrayList<ComboDisplayFormatContentProposal>();

            // Разбиваем фильтруемый текст на слова
            StringTokenizer tokenizerFilterText = new StringTokenizer(contents);

            List<String> worlds = new ArrayList<String>();
            while (tokenizerFilterText.hasMoreElements()) {
                worlds.add(((String) tokenizerFilterText.nextElement()).toLowerCase());
            }

            for (String s : contentProposals.keySet()) {
                boolean containsAllWorlds = true;
                for (String world : worlds) {
                    if (!s.contains(world)) {
                        containsAllWorlds = false;
                        break;
                    }
                }
                if (containsAllWorlds) result.add(contentProposals.get(s));
            }

            resultArray = result.toArray(new IContentProposal[result.size()]);
            cache.put(contents, resultArray);
            return resultArray;
        }
    };


    public AutoCompleteCombo(Composite parent, int style, List<T> autocompleteData, ComboDisplayFormat<T> displayFormat) {
        super(parent, SWT.NONE);
        FillLayout fl = new FillLayout();
        fl.marginHeight = 0;
        fl.marginWidth = 0;
        setLayout(fl);
        this.displayFormat = displayFormat;
        setAutocompleteData(autocompleteData);
        text = new Text(this, style);
        text.addVerifyListener(new VerifyListener() {
            @Override
            public void verifyText(VerifyEvent e) {
                StringBuilder newText = new StringBuilder(text.getText());
                newText.replace(e.start, e.end, e.text);
                if (" ".equals(newText.toString())) return;

                e.doit = (provider.getProposals(newText.toString(), 0).length) != 0;
                if (!e.doit) {
                    text.getDisplay().beep();
                    if (text.getText().isEmpty()) text.setText(" ");
                }
            }
        });

        adapter = new ContentProposalAdapter(text, new ContentAdapter(), provider, null, null);
        adapter.setPropagateKeys(true);
        adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);
    }


    public class ContentAdapter extends TextContentAdapter {

        @Override
        public void setControlContents(Control control, String contents, int cursorPosition) {
            selected = idToItems.get(contents);
            text.setText(displayFormat.getDisplayName(selected));
            text.setSelection(cursorPosition, cursorPosition);
            fireItemSelected(selected);
        }

        @Override
        public void insertControlContents(Control control, String contents, int cursorPosition) {
            selected = idToItems.get(contents);
            text.setText(displayFormat.getDisplayName(selected));
            text.setSelection(cursorPosition, cursorPosition);
            fireItemSelected(selected);
        }


    }

    private List<T> autocompleteData;

    public void setAutocompleteData(List<T> autocompleteData) {
        if (autocompleteData == null) autocompleteData = new ArrayList<T>();
        this.autocompleteData = autocompleteData;
        contentProposals = new Hashtable<String, ComboDisplayFormatContentProposal>(autocompleteData.size());

        for (T element : autocompleteData) {
            contentProposals.put(displayFormat.getDisplayName(element).toLowerCase(), new ComboDisplayFormatContentProposal(displayFormat, element));
            idToItems.put(displayFormat.getPrimaryKey(element), element);
        }
    }

    public AutoCompleteCombo(Composite parent, int style, List<T> data) {
        this(parent, style, data, new DefaultComboDisplayFormat<T>());
    }


}
